package com.twinkle.dbmanage.ui;

import com.twinkle.dbmanage.dao.ICommonDao;
import com.twinkle.dbmanage.dao.impl.ICommonDaoImpl;
import com.twinkle.dbmanage.vo.DBConfig;
import com.twinkle.dbmanage.vo.DBField;

import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Twinkle
 */
public class MainFrame extends JFrame {

    /* 窗口初始化参数 */

    private static final int MAIN_WINDOW_WIDTH = 800;
    private static final int MAIN_WINDOW_HEIGHT = 600;

    private DBConfig config;
    private ICommonDao commonDao;
    private String dbName;

    private JMenuBar menuBar;
    private JMenu toolMenu, helpMenu;
    private JMenuItem configItem, executeItem, quitItem, aboutItem;

    /* 主体控件 */

    private JSplitPane splitPane;
    private JPanel treePanel, operatorPanel;

    /* 左侧控件 */

    private JScrollPane treeScrollPane;
    private JTree tree;

    /* 右侧控件 */

    private JSplitPane rightSplitPane;
    private JScrollPane sqlInputScrollPane, sqlStructScrollPane, sqlResultScrollPane;
    private JTabbedPane tabPane;
    private JTextArea jta;
    private JTable structTable, resultTable;
    private SelfTableModel<DBField> structTableModel;
    private SelfTableModel<Object[]> resultTableModel;

    public MainFrame(DBConfig dbc) {
        this.config = dbc;
        commonDao = new ICommonDaoImpl(config);
        String url = this.config.getUrl();
        int startIndex = url.lastIndexOf("/");
        int endIndex = url.lastIndexOf("?");
        dbName = url.substring(startIndex + 1, endIndex);
        initAppUI();
        //打印登录信息
        System.out.println(config.toString());
    }

    private void initAppUI() {
        initComponent();
        addComponent();
        addListener();
        initWindows();
    }

    private void initComponent() {
        /* 左侧初始化 */
        DefaultMutableTreeNode top = new DefaultMutableTreeNode(dbName);
        List<String> tableNameList = commonDao.getTableName(dbName);
        tableNameList.forEach(name -> {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode(name);
            top.add(node);
        });
        tree = new JTree(top);
        treeScrollPane = new JScrollPane(tree);

        /* 右侧初始化 */

        rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        jta = new JTextArea();
        jta.setFont(new Font("Consolas", Font.BOLD, 24));
        sqlInputScrollPane = new JScrollPane(jta);
        structTableModel = new SelfTableModel<>(new ArrayList<DBField>(), new String[]{"字段名", "字段类型", "大小"});
        structTableModel.setColumnOrder(0, "fieldName");
        structTableModel.setColumnOrder(1, "fieldType");
        structTableModel.setColumnOrder(2, "fieldSize");
        structTable = new JTable(structTableModel);
        sqlStructScrollPane = new JScrollPane(structTable);

        resultTableModel = new SelfTableModel<>(new ArrayList<>(), new String[]{});
        resultTable = new JTable(resultTableModel);
        sqlResultScrollPane = new JScrollPane(resultTable);
        tabPane = new JTabbedPane();

        treePanel = new JPanel();
        operatorPanel = new JPanel();
        splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);

        configItem = new JMenuItem("参数设置");
        executeItem = new JMenuItem("执行");
        executeItem.setAccelerator(KeyStroke.getKeyStroke('R', InputEvent.CTRL_DOWN_MASK));
        quitItem = new JMenuItem("退出");
        aboutItem = new JMenuItem("关于");
        toolMenu = new JMenu("工具");
        helpMenu = new JMenu("帮助");
        menuBar = new JMenuBar();

    }

    private void addComponent() {

        /* 右侧添加控件 */

        tabPane.add("表结构", sqlStructScrollPane);
        tabPane.add("操作结果", sqlResultScrollPane);

        rightSplitPane.setTopComponent(sqlInputScrollPane);
        rightSplitPane.setBottomComponent(tabPane);
        rightSplitPane.setDividerLocation(200);
        rightSplitPane.setEnabled(false);
        rightSplitPane.setDividerSize(2);

        operatorPanel.setLayout(new BorderLayout());
        operatorPanel.add(rightSplitPane);

        /* 左侧添加控件 */
        treePanel.setLayout(new BorderLayout());
        treePanel.add(treeScrollPane);

        splitPane.setLeftComponent(treePanel);
        splitPane.setRightComponent(operatorPanel);
        splitPane.setDividerLocation(200);
        splitPane.setEnabled(false);
        splitPane.setDividerSize(2);

        toolMenu.add(configItem);
        toolMenu.add(executeItem);
        toolMenu.addSeparator();
        toolMenu.add(quitItem);
        helpMenu.add(aboutItem);
        menuBar.add(toolMenu);
        menuBar.add(helpMenu);
        this.setJMenuBar(menuBar);

        this.add(splitPane);
    }

    private void addListener() {
        executeItem.addActionListener(
                new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        tabPane.setSelectedIndex(1);
                        String sql = jta.getSelectedText();
                        System.out.println("==== 待执行 SQL 语句：" + sql);
                        if (sql == null) {
                            Object[] msg = new Object[]{"未选中待执行的SQL语句", "请选中需要执行的SQL语句后再点击执行按钮"};
                            List<Object[]> dataList = new ArrayList<>();
                            dataList.add(msg);
                            resultTableModel.setDataList(dataList);
                            resultTableModel.setHeader(new String[]{"错误！"});
                        } else {
                            if (sql.toUpperCase().startsWith("SELECT")) {
                                List<Object[]> dataList = commonDao.getExecuteResult(sql);
                                String[] dataHeader = commonDao.getTableHeader();
                                resultTableModel.setDataList(dataList);
                                resultTableModel.setHeader(dataHeader);
                            } else {
                                int rows = commonDao.getExecuteRowsCount(sql);
                                Object[] msg = new Object[]{"受影响行数：" + rows};
                                List<Object[]> dataList = new ArrayList<>();
                                dataList.add(msg);
                                resultTableModel.setDataList(dataList);
                                resultTableModel.setHeader(new String[]{"返回信息"});
                            }
                        }
                        ((AbstractTableModel) resultTableModel).fireTableDataChanged();
                        ((AbstractTableModel) resultTableModel).fireTableStructureChanged();
                    }
                }
        );
        quitItem.addActionListener(
                new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        MainFrame.this.dispose();
                    }
                }
        );
        tree.addTreeSelectionListener(
                new TreeSelectionListener() {
                    @Override
                    public void valueChanged(TreeSelectionEvent e) {
                        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                        if (node.isLeaf()) {
                            tabPane.setSelectedIndex(0);
                            String tableName = (String) node.getUserObject();
                            List<DBField> dataList = commonDao.getFieldInfo(dbName, tableName);
                            structTableModel.setDataList(dataList);
                            structTable.updateUI();

                        }
                    }
                }
        );

    }

    private void initWindows() {
        this.setTitle("DatabaseManager-Main");
        this.setSize(MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}
